﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SqlImEx.Sql;
using System.IO;
using System.Data;
using SqlImEx.Util;
using SqlImEx.Xml;
using System.Text.RegularExpressions;

namespace SqlImEx
{
    public class Exporter
    {
        ISqlContext _context;
        string _path;
        string _fieldDelimiter = "Æ";
        string _rowDelimiter = "ñ";
        string _beginTableDelimiter = "ڻ";
        string _endTableDelimiter = "ÿ";
        string _nullvalue = "Ǿ";
        public Exporter(ISqlContext context, string path)
        {
            _context = context;
            _context.KeepAlive = true;
            _path = path;
        }

        private Action<string> _debugWrite = delegate { };
        public Action<string> DebugWrite
        {
            get { return _debugWrite; }
            set { _debugWrite = value; }
        }

        public Configuration Configuration { get; set; }

        public void Export()
        {
            using (var sw = new StreamWriter(_path))
            {
                var tables = _context.GetTableData();
                if (Configuration != null && Configuration.List != null && Configuration.List.Search.Count() > 0)
                {
                    var patterns = Configuration.List.Search.Select(x => x.pattern);
                    tables = tables.Where(x =>
                        {
                            return patterns.Any(p => Regex.IsMatch(x.FullSqlName, p));
                        }).ToList();
                }

                if (Configuration != null && Configuration.Markup != null)
                {
                    if (!string.IsNullOrEmpty(Configuration.Markup.FieldDelimiter))
                        _fieldDelimiter = Configuration.Markup.FieldDelimiter;
                    if (!string.IsNullOrEmpty(Configuration.Markup.RowDelimiter))
                        _rowDelimiter = Configuration.Markup.RowDelimiter;
                    if (!string.IsNullOrEmpty(Configuration.Markup.TableStartDelimiter))
                        _beginTableDelimiter = Configuration.Markup.TableStartDelimiter;
                    if (!string.IsNullOrEmpty(Configuration.Markup.TableEndDelimiter))
                        _endTableDelimiter = Configuration.Markup.TableEndDelimiter;
                    if (!string.IsNullOrEmpty(Configuration.Markup.NullValue))
                        _nullvalue = Configuration.Markup.NullValue;
                }

                sw.WriteLine("[settings]");
                sw.WriteLine(string.Format("fd={0}", _fieldDelimiter));
                sw.WriteLine(string.Format("rd={0}", _rowDelimiter));
                sw.WriteLine(string.Format("bt={0}", _beginTableDelimiter));
                sw.WriteLine(string.Format("et={0}", _endTableDelimiter));
                sw.WriteLine(string.Format("nv={0}", _nullvalue));
                sw.WriteLine("[data]");

                foreach (var tbl in tables)
                {
                    DebugWrite(tbl.FullyQualifiedSqlName);
                    sw.WriteLine(_beginTableDelimiter);
                    sw.WriteLine(tbl.FullyQualifiedSqlName);
                    _context.GetFieldData(tbl);

                    sw.WriteLine(tbl.Field.DelimitedString(f => f.name, _fieldDelimiter));
                    _context.GetAllRows(tbl, r => sw.WriteLine(tbl.Field.DelimitedString(f => GetFieldValue(r[f.name]), _fieldDelimiter) + _rowDelimiter));
                    sw.WriteLine(_endTableDelimiter);
                }
                sw.Close();
            }
        }

        private string GetFieldValue(object dbval)
        {
            string val;
            if (dbval == DBNull.Value)
                val = _nullvalue;
            else
            {
                if (dbval is byte[])
                    val = Convert.ToBase64String((byte[])dbval);
                else if (dbval is bool)
                    val = (bool)dbval == true ? "1" : "0";
                else if (dbval is DateTime)
                    val = ((DateTime)dbval).ToString("yyyy-MM-dd HH:mm:ss");
                else
                    val = dbval.ToString();
            }
            if (val.Contains(_fieldDelimiter))
                throw new Exception(_fieldDelimiter + " found in data");
            if (val.Contains(_fieldDelimiter))
                throw new Exception(_rowDelimiter + " found in data");
            return val;
        }
    }
}
